package com.ym521.logdog.engine

import android.os.Handler
import android.os.Looper
import android.os.Message
import android.util.Log
import com.ym521.logdog.core.IDiskLogEngine
import com.ym521.logdog.core.LogDogConfig
import com.ym521.logdog.core.LogPriority
import com.ym521.logdog.utils.AESecurityUtil
import com.ym521.logdog.utils.DateUtil
import com.ym521.logdog.utils.StringCodeUtil
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException

/**
 *@author Ym
 *E-mail: 2435970206@qq.com
 *createTime:2024/7/26
 *explain: Crash 日志写入文件
 *
 */
class DiskCrashLogEngine private constructor(looper: Looper) :
    Handler(looper), IDiskLogEngine {

    companion object {
        private const val TAG = "DiskCrashLogEngine"
        private var engine: DiskCrashLogEngine? = null

        @Synchronized
        fun create(looper: Looper): DiskCrashLogEngine {
            return engine ?: DiskCrashLogEngine(looper)
        }
    }

    override fun logWrite(priority: LogPriority, tag: String, msg: String) {
        val msgContent =
            if (LogDogConfig.isLogFileAES && LogDogConfig.logFileAES_key.isNotBlank()) {
                val keyBytes = LogDogConfig.logFileAES_key.toByteArray(Charsets.UTF_8)
                AESecurityUtil.encrypt(msg, keyBytes)
            } else {
                msg
            }
        val message = this.obtainMessage()
        val dateTiem = DateUtil.currentDateMessage()
        message.obj = "CRASH    $dateTiem    $tag    $msgContent \n"
        this.sendMessage(message)
    }

    override fun handleMessage(msg: Message) {
        try {
            val logMessage = msg.obj as String
            writeCrashLogFile(logMessage)
        } catch (e: Exception) {
            Log.e(TAG, "$e")
        }
    }


    /**
     * 写入 Crash日志文件
     */
    private fun writeCrashLogFile(logMsg: String) {
        val crashLogFile = logCrashFileCut()
        var buff: BufferedOutputStream? = null
        try {
            if (!crashLogFile.exists()) {
                crashLogFile.parentFile?.mkdirs()
                crashLogFile.createNewFile()
            }
            buff = BufferedOutputStream(FileOutputStream(crashLogFile, true))
            if (LogDogConfig.encoding) {
                buff.write(StringCodeUtil.encryptionString(logMsg))
            } else {
                buff.write(logMsg.toByteArray(Charsets.UTF_8))
            }
        } catch (e: IOException) {
            Log.e(TAG, e.toString())
        } finally {
            buff?.flush()
            buff?.close()
        }
    }

    private fun logCrashFileCut(): File {
        val fileName = "crash_${DateUtil.currentDateFile()}.log"
        val crashLogFile = File(DiskLogEngineFactory.ROOT_DIR, fileName)
        //不存在 日志文件 不需要分割
        if (!crashLogFile.exists()) return crashLogFile
        //日志文件分割
        if (crashLogFile.length() <= 1024 * 1024 * LogDogConfig.logFileSize) {
            return crashLogFile
        } else {
            var logFileSum = 0
            while (true) {
                logFileSum++
                val fileName = "crash_${DateUtil.currentDateFile()}_$logFileSum.log"
                val crashLogFile = File(DiskLogEngineFactory.ROOT_DIR, fileName)
                if (!crashLogFile.exists()) {
                    return crashLogFile
                }
            }
        }
    }

}